/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.sharding.client.util;

import java.lang.reflect.Field;
import java.util.Comparator;

public class ComparatorUtil implements Comparator {

    //Property name to sort
    private String name;
    //Ascending order
    private boolean flag;

    /**
     * @param name The property name to be sorted. If it is a basic type of sorting, enter a null value
     * @param flag true/false : Ascending / descending
     */
    public ComparatorUtil(String name, boolean flag) {
        super();
        this.name = name;
        this.flag = flag;
    }

    @Override
    public int compare(Object o1, Object o2) {
        int result = 0;
        //The input parameter is null | the parameter types are not equal and will not be processed.
        if (o1 == null || o2 == null || !o1.getClass().getName().equals(o2.getClass().getName())) {
            return result;
        }
        //Processing of 7 basic types (except Boolean, and collections. Reverse() / collections. Sort())
        if (isBaseType(o1)) {
            //compare
            return baseTypeOpt(o1, o2);
        }
        try {
            Field f1 = o1.getClass().getDeclaredField(name);
            Field f2 = o2.getClass().getDeclaredField(name);
            //Set private readable
            f1.setAccessible(true);
            f2.setAccessible(true);
            result = baseTypeOpt(f1.get(o1), f2.get(o2));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private int baseTypeOpt(Object o1, Object o2) {
        int result = 0;
        if (o1 instanceof String) {
            result = o1.toString().compareTo(o2.toString());
        } else if (o1 instanceof Integer) {
            result = ((Integer) o1) - ((Integer) o2);
        } else if (o1 instanceof Double) {
            if (((Double) o1 - (Double) o2) > 0) {
                result = 1;
            } else if (((Double) o1 - (Double) o2) < 0) {
                result = -1;
            }
        } else if (o1 instanceof Float) {
            if (((Float) o1 - (Float) o2) > 0) {
                result = 1;
            } else if (((Float) o1 - (Float) o2) < 0) {
                result = -1;
            }
        } else if (o1 instanceof Character) {
            result = ((Character) o1).compareTo(((Character) o2));
        } else if (o1 instanceof Short) {
            result = ((Short) o1) - ((Short) o2);
        } else if (o1 instanceof Long) {
            if (((Long) o1 - (Long) o2) > 0) {
                result = 1;
            } else if (((Long) o1 - (Long) o2) < 0) {
                result = -1;
            }
        }
        //Descending order
        if (!isFlag()) {
            result = -result;
        }
        return result;
    }

    private boolean isBaseType(Object o) {
        if ((o instanceof String) || (o instanceof Integer)
                || (o instanceof Double) || (o instanceof Float)
                || (o instanceof Character) || (o instanceof Short)
                || (o instanceof Long)) {
            return true;
        }
        return false;
    }

    public boolean isFlag() {
        return flag;
    }
}
